Release: Merge develop into main - QR Code features, Sub-app redirects, and Summary Doc fixes - #286
Release: Merge develop into main - QR Code features, Sub-app redirects, and Summary Doc fixes#286amitsinghsutara wants to merge 12 commits into
Conversation
…host hosted sub apps
feat: Adding Qr-code Functionality in Cr-container for copying cr_user_id!
fix: [MR-175] add debug-only custom cr_user_id and local sub-app redirect
fix: [MR-187] set updated_at alongside created_at on summary doc creation
This reverts commit 1a45c19.
📝 WalkthroughWalkthroughThe change adds QR-based identity display, debug custom user-ID support, local sub-app URL redirection, debug loopback networking, and local configuration documentation. It also adds ZXing and uses one timestamp for new summary document fields. ChangesDebug identity and local development
Estimated code review effort: 3 (Moderate) | ~25 minutes Mergeability Score: 🟡 Moderate · up to The PR adds QR controls, redirect behavior, and debug configuration, but the current build configuration declares conflicting Android Gradle Plugin versions that can prevent a reliable release build until resolved. Minor follow-up is also needed for analytics identity, localization, and custom-ID persistence. Sequence Diagram(s)sequenceDiagram
participant MainActivity
participant QR_overlay
participant QRCodeWriter
participant ClipboardManager
MainActivity->>QRCodeWriter: Encode cached user ID
QRCodeWriter-->>MainActivity: Return QR bitmap
MainActivity->>QR_overlay: Show QR bitmap and user ID
QR_overlay->>ClipboardManager: Copy formatted user ID
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/main/java/org/curiouslearning/container/MainActivity.java`:
- Line 1102: Register an OnDismissListener for the language dialog after
customUserIdField is initialized, and persist the custom ID through
persistCustomUserId(customUserIdField) when the dialog is dismissed, including
via Back. Keep the existing persistence calls unchanged.
Apply the same fix in
`@app/src/main/java/org/curiouslearning/container/MainActivity.java` around lines
1223 - 1230: Covered by the shared dismissal persistence and handler-refresh
remediation.
In `@app/src/main/java/org/curiouslearning/container/WebApp.java`:
- Around line 105-107: Update the analytics event calls in WebApp so both app
launch and app exit events pass identityUrl() as the web app URL, rather than
appUrl or the local URL. Reuse the existing identityUrl() method and leave other
event fields unchanged.
In `@app/src/main/res/layout/activity_main.xml`:
- Around line 120-122: Replace the hard-coded QR accessibility descriptions and
copy instruction with shared localized string resources across all variants:
app/src/main/res/layout/activity_main.xml lines 120-122, 175-180, and 195-201;
app/src/main/res/layout-sw600dp/activity_main.xml lines 127-129, 163-168, and
181-187; and app/src/main/res/layout-sw720dp/activity_main.xml lines 128-130,
164-169, and 182-188. Add or reuse appropriate entries in the string resources,
preserving the existing show-button, QR-image, and copy-instruction text.
In `@gradle/wrapper/gradle-wrapper.properties`:
- Line 2: Update the Android Gradle Plugin declarations in build.gradle to
remove the outdated 7.3.1 entries, keeping the project consistently on AGP
8.13.1 alongside Gradle 9.2.1 and Java 17.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 0195759f-5427-43ac-a601-84ff72d3f30f
⛔ Files ignored due to path filters (2)
.claude/skills/test-subapp-locally/SKILL.mdis excluded by!**/*.mdapp/src/main/res/drawable/coaches_icon_cr.pngis excluded by!**/*.png
📒 Files selected for processing (15)
app/build.gradleapp/fastlane/debug_apks/app-debug.apkapp/src/debug/AndroidManifest.xmlapp/src/debug/res/xml/network_security_config.xmlapp/src/main/java/org/curiouslearning/container/MainActivity.javaapp/src/main/java/org/curiouslearning/container/WebApp.javaapp/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.javaapp/src/main/java/org/curiouslearning/container/presentation/adapters/WebAppsAdapter.javaapp/src/main/res/layout-sw600dp/activity_main.xmlapp/src/main/res/layout-sw720dp/activity_main.xmlapp/src/main/res/layout/activity_main.xmlapp/src/main/res/layout/language_popup.xmlapp/src/main/res/values/strings.xmlgradle/wrapper/gradle-wrapper.propertieslocal.properties.example
| @Override | ||
| public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | ||
| audioPlayer.play(MainActivity.this, R.raw.sound_button_pressed); | ||
| persistCustomUserId(customUserIdField); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Persist and apply the custom ID on every dialog dismissal.
The custom-ID dialog remains cancelable, so pressing Back can bypass the existing persistence calls. Persist the field from the cancellation or dismissal path, then refresh the shared handler after editor.apply() so existing WebApp.WebAppInterface instances use the updated value.
📍 Affects 1 file
app/src/main/java/org/curiouslearning/container/MainActivity.java#L1102-L1102(this comment)app/src/main/java/org/curiouslearning/container/MainActivity.java#L1223-L1230
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/main/java/org/curiouslearning/container/MainActivity.java` at line
1102, Register an OnDismissListener for the language dialog after
customUserIdField is initialized, and persist the custom ID through
persistCustomUserId(customUserIdField) when the dialog is dismissed, including
via Back. Keep the existing persistence calls unchanged.
Apply the same fix in
`@app/src/main/java/org/curiouslearning/container/MainActivity.java` around lines
1223 - 1230: Covered by the shared dismissal persistence and handler-refresh
remediation.
| private String identityUrl() { | ||
| return (localDevOriginalUrl != null && !localDevOriginalUrl.isEmpty()) ? localDevOriginalUrl : appUrl; | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the analytics implementation before inspecting its URL handling.
fd -t f 'AnalyticsUtils\.java|AnalyticsUtils\.(kt|java)' app | while IFS= read -r file; do
ast-grep outline "$file" --items all
rg -n -C 5 'logEvent|app_launch|app_exit|appUrl|url' "$file"
done
# Find callers and tests that define the event URL contract.
rg -n -C 4 'AnalyticsUtils\.logEvent|logAppLaunchEvent|logAppExitEvent' appRepository: curiouslearning/CRcontainer
Length of output: 17200
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect how WebApp assigns appUrl and localDevOriginalUrl before analytics calls.
cat -n app/src/main/java/org/curiouslearning/container/WebApp.java | sed -n '1,125p;575,600p'
# Check tests and all AnalyticsUtils.logEvent callers for the expected web_app_url value.
rg -n -C 6 'localDevOriginalUrl|identityUrl|AnalyticsUtils\.logEvent|web_app_url' app/src/test app/src/main app/src/androidTest 2>/dev/null || true
# Model the analytics contract from the source without executing repository code.
python3 - <<'PY'
from pathlib import Path
src = Path("app/src/main/java/org/curiouslearning/container/firebase/AnalyticsUtils.java").read_text()
assert 'bundle.putString("web_app_url", appUrl);' in src
print("AnalyticsUtils.logEvent stores its appUrl parameter as web_app_url.")
PYRepository: curiouslearning/CRcontainer
Length of output: 24946
Use identityUrl() for analytics events.
AnalyticsUtils.logEvent() stores the URL as web_app_url. Pass identityUrl() to both app launch and app exit events to avoid recording localhost for redirected launches.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/main/java/org/curiouslearning/container/WebApp.java` around lines 105
- 107, Update the analytics event calls in WebApp so both app launch and app
exit events pass identityUrl() as the web app URL, rather than appUrl or the
local URL. Reuse the existing identityUrl() method and leave other event fields
unchanged.
| android:src="@drawable/coaches_icon_cr" | ||
| android:background="@android:color/transparent" | ||
| android:contentDescription="Show QR Code ID" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Move the QR UI text to string resources.
The visible labels and accessibility descriptions are hard-coded in each layout variant. Localized builds cannot translate these QR controls.
app/src/main/res/layout/activity_main.xml#L120-L122: replace the show-button description with an@stringreference.app/src/main/res/layout/activity_main.xml#L175-L180: replace the QR image description with an@stringreference.app/src/main/res/layout/activity_main.xml#L195-L201: replace the copy instruction with an@stringreference.app/src/main/res/layout-sw600dp/activity_main.xml#L127-L129: replace the show-button description with an@stringreference.app/src/main/res/layout-sw600dp/activity_main.xml#L163-L168: replace the QR image description with an@stringreference.app/src/main/res/layout-sw600dp/activity_main.xml#L181-L187: replace the copy instruction with an@stringreference.app/src/main/res/layout-sw720dp/activity_main.xml#L128-L130: replace the show-button description with an@stringreference.app/src/main/res/layout-sw720dp/activity_main.xml#L164-L169: replace the QR image description with an@stringreference.app/src/main/res/layout-sw720dp/activity_main.xml#L182-L188: replace the copy instruction with an@stringreference.
📍 Affects 3 files
app/src/main/res/layout/activity_main.xml#L120-L122(this comment)app/src/main/res/layout/activity_main.xml#L175-L180app/src/main/res/layout/activity_main.xml#L195-L201app/src/main/res/layout-sw600dp/activity_main.xml#L127-L129app/src/main/res/layout-sw600dp/activity_main.xml#L163-L168app/src/main/res/layout-sw600dp/activity_main.xml#L181-L187app/src/main/res/layout-sw720dp/activity_main.xml#L128-L130app/src/main/res/layout-sw720dp/activity_main.xml#L164-L169app/src/main/res/layout-sw720dp/activity_main.xml#L182-L188
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/main/res/layout/activity_main.xml` around lines 120 - 122, Replace
the hard-coded QR accessibility descriptions and copy instruction with shared
localized string resources across all variants:
app/src/main/res/layout/activity_main.xml lines 120-122, 175-180, and 195-201;
app/src/main/res/layout-sw600dp/activity_main.xml lines 127-129, 163-168, and
181-187; and app/src/main/res/layout-sw720dp/activity_main.xml lines 128-130,
164-169, and 182-188. Add or reuse appropriate entries in the string resources,
preserving the existing show-button, QR-image, and copy-instruction text.
| @@ -1,5 +1,5 @@ | |||
| distributionBase=GRADLE_USER_HOME | |||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip | |||
| distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip | |||
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
fd -t f -a '^(build\.gradle|build\.gradle\.kts|settings\.gradle|settings\.gradle\.kts|libs\.versions\.toml|gradle\.properties)$' . \
-x rg -n -C2 'com\.android\.application|com\.android\.tools\.build:gradle|agp|org\.gradle\.java\.home|JavaVersion|jvmToolchain' {}Repository: curiouslearning/CRcontainer
Length of output: 892
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- matching build files ---'
fd -t f -a '^(build\.gradle|build\.gradle\.kts|settings\.gradle|settings\.gradle\.kts|libs\.versions\.toml|gradle\.properties)$' . \
-x sh -c 'echo "### $1"; cat -n "$1"' sh {}
printf '%s\n' '--- wrapper metadata ---'
fd -t f -a 'gradle-wrapper\.properties$' . \
-x sh -c 'echo "### $1"; cat -n "$1"' sh {}Repository: curiouslearning/CRcontainer
Length of output: 13600
🌐 Web query:
Android Gradle Plugin 8.13.1 Gradle 9.2.1 compatibility official documentation
💡 Result:
Yes, Android Gradle Plugin (AGP) 8.13.1 is compatible with Gradle 9.2.1 [1]. Official documentation from Gradle indicates that Gradle 9.2.1 has been tested and is compatible with Android Gradle Plugin versions ranging from 8.4 through 8.13 [1]. While AGP 8.x series was primarily designed for Gradle 8.x, Gradle maintained support for these plugin versions in the 9.x series up to version 9.5 [2]. For your specific configuration: - Android Gradle Plugin 8.13.1 [3] - Gradle 9.2.1 [1] This combination falls within the supported range verified by the Gradle compatibility matrix [1]. As a general best practice, it is recommended to keep both your plugin and Gradle wrapper updated to their latest stable versions to ensure optimal performance and security [4].
Citations:
- 1: https://docs.gradle.org/9.2.1/userguide/compatibility.html
- 2: Gradle 9.6.0 RC1 incompatible with Android Gradle Plugin 8.13.2 gradle/gradle#38073
- 3: https://mvnrepository.com/artifact/com.android.tools.build/gradle/8.13.1/dependencies
- 4: https://developer.android.com/build/releases/about-agp
🌐 Web query:
site:developer.android.com/build/releases Android Gradle Plugin 9.0 Gradle 9.1 compatibility
💡 Result:
Android Gradle Plugin (AGP) 9.0 is compatible with Gradle 9.1.0 and higher [1]. Specifically, AGP 9.0 requires a minimum Gradle version of 9.1.0 [2][1]. For the best performance and compatibility, it is recommended to use the latest versions of both the Android Gradle Plugin and Gradle [1]. As of August 2026, later versions of AGP are available, such as AGP 9.1.1, which requires a minimum Gradle version of 9.3.1 [3][4], and AGP 9.4.0, which requires Gradle 9.6.0 [5].
Citations:
- 1: https://developer.android.com/build/releases/about-agp
- 2: https://developer.android.com/build/releases/agp-9-0-0-release-notes
- 3: https://developer.android.com/build/releases/agp-9-1-0-release-notes
- 4: https://developer.android.com/build/releases/agp-9-1-0-release-notes?authuser=0
- 5: https://developer.android.com/build/releases/agp-9-4-0-release-notes
🌐 Web query:
Gradle plugin request already on classpath with a different version buildscript plugins block Android Gradle Plugin
💡 Result:
The error "Plugin request for plugin already on the classpath must not include a version" occurs in Gradle when a plugin is requested with a version in a plugins block, but that plugin is already present on the build classpath (e.g., loaded by the root project, buildSrc, or pluginManagement blocks) [1][2]. Because Gradle does not allow multiple versions of the same plugin to exist in the same build, it rejects any request that attempts to define a version when one is already established [1][3]. To resolve this issue, follow these standard practices: 1. Define the Version Once: Centralize the plugin version in your root build.gradle.kts file or in settings.gradle.kts using the pluginManagement block [1][3]. 2. Use apply false in the Root: When defining the version in the root project, use apply false to add the plugin to the classpath without applying it to the root project itself [1][4][3]. kotlin // In root build.gradle.kts plugins { id("com.android.application") version "8.x.x" apply false } 3. Omit the Version in Subprojects: In your module-level build.gradle.kts files, apply the plugin without specifying the version [1][4][3]. This tells Gradle to use the version already available on the classpath [4]. kotlin // In module build.gradle.kts plugins { id("com.android.application") } If you are using Version Catalogs (libs.versions.toml), this issue often arises when using alias(libs.plugins.xxx) in modules, as alias typically includes the version [5][4]. In such cases, if the plugin is already on the classpath, you may need to use id to reference the plugin ID directly instead of using the alias, or ensure the version is only defined in the root where it is first applied [5][6][4]. For the Android Gradle Plugin (AGP), strictly enforce the same version across all modules and included builds [7]. AGP contains internal logic that specifically checks for version consistency and will throw an error if multiple versions are detected within the same build process [7].
Citations:
- 1: https://stackoverflow.com/questions/60070739/plugin-request-for-plugin-already-on-the-classpath-must-not-include-a-version
- 2: https://discuss.gradle.org/t/error-plugin-already-on-the-classpath-must-not-include-a-version/31814
- 3: https://www.exchangetuts.com/plugin-request-for-plugin-already-on-the-classpath-must-not-include-a-version-1640357343724476
- 4: https://discuss.gradle.org/t/multi-module-project-how-where-to-apply-plugins/46701
- 5: The request for this plugin could not be satisfied because the plugin is already on the classpath with an unknown version gradle/gradle#20084
- 6: Version Catalogs: Omit version for plugins already on the classpath gradle/gradle#18236
- 7: https://android.googlesource.com/platform/tools/base/%2B/studio-master-dev/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/agpVersionChecker.kt
🌐 Web query:
site:docs.gradle.org plugin already on the classpath with a different version
💡 Result:
The error "plugin already on the classpath with a different version" typically occurs in build tools like Gradle when a project attempts to load the same plugin with conflicting version requirements [1]. Because plugins share the same classloader, Gradle and other build systems cannot safely load two different versions of the same plugin simultaneously [1]. To troubleshoot and resolve this issue, consider the following approaches based on the dependency graph: 1. Identify the Conflict: Use built-in diagnostic tools to understand where the conflicting versions are coming from. In Gradle, the dependencyInsight task is the primary tool for this [2]. You can run:./gradlew dependencyInsight --configuration <configuration_name> --dependency <plugin_id> This report will show you the "Selection reasons," identifying which parts of your project or transitive dependencies are requesting the different versions [2]. 2. Align Plugin Versions: The most common fix is to ensure all parts of your build configuration request the same version of the plugin [3][4]. If a transitive dependency is pulling in an older or different version, you can force a specific version in your top-level build script or settings file to override it [3][5]. 3. Use Plugin Management: If you are managing multiple sub-projects, define the plugin versions in your settings.gradle (or settings.gradle.kts) file using the pluginsManagement block [6]. This centralizes the version definition, preventing individual modules from accidentally requesting conflicting versions [6]. 4. Check for Capability Conflicts: In some cases, the error relates to "capabilities" where different modules (or different versions of the same relocated module) provide the same feature [7][8]. If this is the cause, you may need to use component metadata rules to explicitly declare them as mutually exclusive or choose a preferred implementation [7][9]. If you are developing a plugin, be aware that plugins can introduce complex dependency graphs [1]. Ensure that your plugin does not transitively include a version of itself or a core library that conflicts with the host project's requirements [1].
Citations:
- 1: https://docs.gradle.org/current/userguide/implementing_gradle_plugins_binary.html
- 2: https://docs.gradle.org/current/userguide/viewing_debugging_dependencies.html
- 3: https://docs.gradle.org/8.13/userguide/dependency_resolution.html
- 4: https://docs.gradle.org/8.10/userguide/dependency_resolution.html
- 5: https://docs.gradle.org/current/userguide/resolution_rules.html
- 6: https://docs.gradle.org/8.11/userguide/plugins.html
- 7: https://docs.gradle.org/8.12.1/userguide/component_capabilities.html
- 8: https://docs.gradle.org/current/userguide/component_capabilities.html
- 9: https://docs.gradle.org/current/userguide/dependencies_intermediate.html
Resolve the Android Gradle Plugin version conflict.
Gradle 9.2.1, Android Gradle Plugin 8.13.1, and Java 17 are compatible. However, build.gradle declares Android Gradle Plugin 8.13.1 and 7.3.1. Remove or update the 7.3.1 declarations before merging.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@gradle/wrapper/gradle-wrapper.properties` at line 2, Update the Android
Gradle Plugin declarations in build.gradle to remove the outdated 7.3.1 entries,
keeping the project consistently on AGP 8.13.1 alongside Gradle 9.2.1 and Java
17.
Summary
This PR merges the latest features and bug fixes from
developintomain.Key Changes
Features
cr_user_id.Bug Fixes & Improvements
updated_atalongsidecreated_atwhen creating the summary document.cr_user_id.CI/CD
Note: The attempt to update the target SDK to 36 was subsequently reverted in this branch.
Summary by CodeRabbit